package prolog.fluents

import java.util.{ArrayList,Iterator};
//import java.util.Iterator;
import prolog.io.IO;

class Queue1 with Cloneable {
  val MIN_QUEUE=4;
  val MAX_QUEUE=1<<24;
  private var head,tail:Int;
  private var queue[]:Object;
  
  def Queue1(size:Int){
    makeIt(size);
  }
  
 def Queue1(){
    this(0);
  }
  
  def Queue1(V:ArrayList){
    this(V.size()+MIN_QUEUE);
    for(var i <- 0 to (V.size()-1)){
          enq(V.get(i));
    }
  }
  
  // synchronized
  private final makeIt(int size):Unit = {
    size=(size<MIN_QUEUE)?MIN_QUEUE:size;
    queue=new Object[size];
    head=tail=0;
    // busy=false;
  }
  
  private final count():Int {
    (head<=tail)?tail-head:queue.length-head+tail;
  }
  
  /**
    Dynamically resizes the queue
  */
  private final requeue(Mes:String):boolean = {
    int newSize=2*count();
    if(newSize>MAX_QUEUE||newSize<MIN_QUEUE)
       false;
    IO.trace(Mes+"!!! "+toString());
    Object[] nqueue=new Object[newSize];
    int j=0;
    for(var i=head;i!=tail;i=inc(i))
      nqueue[j++]=queue[i];
    queue=nqueue;
    head=0;
    tail=j;
     true;
  }
  
  // synchronized
  def final enq(V:Object):boolean = {
    // enterCritical();
    if(inc(tail)==head) { // full !!!
      if(!requeue("expanding")) {
        IO.errmes("Warning: queue overflow at:"+V);
        false;
      }
    }
    queue[tail]=V;
    tail=inc(tail);
    // exitCritical();
    true;
  }

  // synchronized
  def final deq():Object = {
    // enterCritical();
    if(tail==head) // empty !!!
      return null;
    if(4*count()<queue.length)
      requeue("shrinking");
    Object V=queue[head];
    head=inc(head);
    // exitCritical();
    V;
  }
  
  private final inc(val:Int):Int ={
     (val+1)%queue.length;
  }
  
  // synchronized
  def final isEmpty() {
    boolean empty;
    // enterCritical();
    empty=tail==head;
    // exitCritical();
     empty;
  }
  
  // synchronized
  def toVector():ArrayList = {
    // enterCritical(); DEADLOCKS!
    ArrayList v=new ArrayList();
    for(var i=head;i!=tail;i=inc(i))
      v.add(queue[i]);
    // exitCritical();
     v;
  }
  
  def toEnumeration():Iterator = {
     toVector().iterator();
  }
  
  def toString():String = {
     count()+"/"+queue.length+"=>"+toVector().toString();
  }
  
} 